/*global Aredis, Acan, Adebug */

// eslint-disable-next-line no-unused-vars
const bcrypt = require('bcrypt')
const Powers = require('./apis/powers')

module.exports = function (app) {
  const errorCall = (error, res) => {
    let code = 31000
    let data = error.data || {}
    if (error.code === 404) code = 32000
    if (error.code === 409) code = 31001
    if (data.code) code = data.code
    if (error.errors) {
      const keys = Object.keys(error.errors)
      if (keys.length > 0) data.param = keys[0]
    }
    data.message = error.message
    res.apiErr(code, data)
  }
  const Apis = {
    errorCall: errorCall,
    create: (req, res) => {
      var post = req.body
      app.service(req.modelName).create(post, {
        inside: true
      }).then(res.apiCb).catch(function (error) {
        Apis.errorCall(error, res)
      })
    },
    update: (req, res) => {
      var get = req.query
      var post = req.body
      if (!get._id) return res.apiErr(31000, { param: '_id', message: '请求参数错误'})
      // app.service(req.modelName).Model.update({_id: get._id, {$set: post}).exec(res.dbCall)
      app.service(req.modelName).patch(get._id, post, {
        inside: true
      }).then(rs=> {
        let data = {n: 0, ok: 1}
        if (rs._id) data.n = 1
        res.apiCb(data)
      }).catch(function (error) {
        errorCall(error, res)
      })
    },
    remove: (req, res) => {
      var post = req.body
      if (!post._id) return res.apiErr(31000, { param: '_id', message: '请求参数错误'})
      if (typeof post._id === 'string') post._id = [post._id]
      if (req.modelName === 'admins' && req.user.username === 'admin') {
        if (post._id.indexOf(req.user._id) !== -1) return res.apiErr(31001, { message: '管理员账号不能删除'})
      }
      // 删除数据清除缓存
      if (['admins', 'roles'].indexOf(req.modelName) !== -1) {
        post._id.forEach((_id) => {
          Aredis.hdel(req.modelName, _id)
        })
      }
      app.service(req.modelName).Model.update({
        _id: {$in: post._id}}, {$set: {del: true}
      }, {
        multi: true
      }).exec((err, rs)=> {
        if (rs && rs.n === 0) {
          return res.apiErr(32000, { message: '数据不存在或已经删除'})
        }
        res.dbCall(err, rs)
      })
    },
    findOne: (req, res) => {
      var get = req.query
      if (!get._id) return res.apiErr(31000, { param: '_id', message: '请求参数错误'})
      app.service(req.modelName).get(get._id, {
        inside: true
      }).then(res.apiCb).catch(function (error) {
        errorCall(error, res)
      })
    },
    find: (req, res) => {
      var get = req.query
      get.$limit = 10
      get.$skip = 0
      if (get.limit) {
        get.$limit = get.limit
        delete get.limit
      }
      if (get.page > 0) {
        get.$skip = get.$limit * (get.page - 1)
        delete get.page
      }
      var dataCall = function (rs) {
        let data = {list: rs.data, total: rs.total, limit: rs.limit, num: rs.data.length}
        data.page = Math.ceil(rs.skip / data.limit) + 1
        res.apiCb(data)
      }
      app.service(req.modelName).find({
        query: get,
        inside: true
      }).then(dataCall).catch(function (error) {
        errorCall(error, res)
      })
    },

    // 获取登录用户信息
    getUser: (req, res, next) => {
      req.user = {}
      if (!req.token) return res.apiErr(30001, { message: '未登录'})
      Aredis.hget('token', req.token, (err, _id) => {
        if (err) return res.apiErr(10001, { message: '缓存故障'})
        if (!Acan.isObjectId(_id)) return res.apiErr(30002, { message: '登录失效'})
        Aredis.hget('admins', _id, (err, rs) => {
          rs = JSON.parse(rs)
          req.user = rs
          let role = rs.role
          if (typeof rs.role === 'string') role = {_id: role}
          Aredis.hget('roles', role._id, (err, rs) => {
            const defRole = {_id: role._id, powers: ['index'], name: ''}
            req.user.role = JSON.parse(rs) || defRole
            Powers.hasPower(req, res, next)
          })
        })
      })
    },
    // 获取应用信息
    getApp: (req, res, next) => {
      var get = req.query
      var call = (rs) => {
        if (get.secret !== rs.secret) return res.apiErr(20001, { message: '应用通信密钥错误' })
        req.Apps = rs
        delete get.appid
        delete get.secret
        next()
      }
      var dbGet = () => {
        app.service('apps').Model.findById(get.appid).then(doc => {
          if (!doc) return call()
          call(doc)
          Aredis.hset('apps', get.appid, JSON.stringify(doc))
        }).catch(call)
      }
      Aredis.hget('apps', get.appid, function (err, rs) {
        rs = JSON.parse(rs)
        if (err) return res.apiErr(10001, { message: '缓存故障'})
        if (!rs || !rs._id) return dbGet()
        call(rs)
      })
    }
  }


  app.apis = Apis
  // app.set('apis', Apis)

  app.use('*', function (req, res, next) {
    var startTime = (new Date()).getTime()
    var urr = req.baseUrl.split('/')
    req.modelName = urr[1] + 's'
    if (req.modelName === 'apis') req.modelName = urr[2] + 's'
    var get = req.query
    var okCode = 30000
    if (req.baseUrl.substr(0, 5) === '/api/') okCode = 20000
    res.apiCb = function (data, ext) {
      app.service('logs').Model.addByApi(startTime, req, 200)
      res.json(Object.assign({code: okCode, data: data}, ext))
    }
    res.apiErr = function (code, error) {
      app.service('logs').Model.addByApi(startTime, req, 400, error)
      res.json({code: code, error: error})
    }
    res.dbCall = function (err, rs) {
      if (err) return res.apiErr(10002, { message: '数据库错误'})
      if (rs.nModified) delete rs.nModified
      res.apiCb(rs)
    }

    req.Aip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || (req.ip ? req.ip.replace('::ffff:', '') : '')
    // 服务接口
    if (urr[1] === 'api') {
      if (!get.appid) {
        //
      }
      if (!get.secret) {
        return res.apiErr(20001, { message: '通信密钥错误' })
      }
    } else if (urr[1] === 'test') {
      // 测试
    } else {
      if (!get.token && urr[2] !== 'login') {
        return res.apiErr(30001, { message: '未登录' })
      }
      req.token = get.token
      delete get.token
    }
    next()
  })

  app.configure(require('./apis/'))

  app.use('/account/login', function (req, res) {
    var post = req.body
    if (!post.username) return res.apiErr(31000, { param: 'username', message: '请输入用户名'})
    if (!post.password) return res.apiErr(31000, { param: 'password', message: '请输入密码'})
    app.service('admins').Model.findOne({
      username: post.username, del: false
    }).populate({ // 获取用户权限
      path: 'role', select: 'name powers del', model: 'role'
    }).then( doc => {
      if (!doc) return res.apiErr(32000, { param: 'username', message: '帐号不存在'})
      let user = doc.toObject()
      if (user.status !== 0) return res.apiErr(30004, { message: '帐号被冻结'})
      if (!user.password) return res.apiErr(30004, { message: '未设置密码'})
      if (bcrypt.compareSync(post.password, user.password)) {
        delete user.password
        // 更新登录时间
        doc.update({
          $set: {last: {login: new Date(), ip: req.Aip}}
        }).then(() => {})
        if (user.role) {
          if (user.role.del) user.role.powers = ['index']
          delete user.role.del
          Aredis.hset('roles', user.role._id, JSON.stringify(user.role))
        }
        delete user.password
        const token = Acan.SHA1(user._id + Acan.time('ms'))
        req.user = user
        Aredis.hset('token', token, user._id)
        Aredis.hset('admins', user._id, JSON.stringify(user))
        res.apiCb(user, {token: token})
      } else {
        return res.apiErr(30005, { param: 'password', message: '密码错误'})
      }
    })
  })

  app.use('/account/logout', Apis.getUser, (req, res)=> {
    Aredis.hdel('token', req.token)
    res.apiCb({})
  })

  app.use('/account/info', Apis.getUser, function (req, res) {
    res.apiCb(req.user)
  })

  app.use('/account/password', Apis.getUser, (req, res)=> {
    var post = req.body
    if (!post.old) return res.apiErr(31000, { param: 'old', message: '请输入原密码'})
    if (!post.password) return res.apiErr(31000, { param: 'password', message: '请输入新密码'})
    if (!post.password2) return res.apiErr(31000, { param: 'password2', message: '请输入确认密码'})
    if (post.password !== post.password2) return res.apiErr(31000, { param: 'password2', message: '确认密码不一致'})
    app.service('admins').get(req.user._id, {
      type: 'account', inside: true
    }).then( user=> {
      if (!bcrypt.compareSync(post.old, user.password)) return res.apiErr(31000, { param: 'old', message: '原密码错误'})
      app.service('admins').patch(req.user._id, {
        password: post.password, password2: post.password2
      }, {
        inside: true
      }).then( rs=> {
        if (rs._id) {
          res.apiCb({n: 1, ok: 1})
        } else {
          res.apiErr(10002, { message: '数据库错误'})
        }
      })
    })
  })

  app.use('/admin/find', Apis.getUser, Apis.find)
  app.use('/admin/findOne', Apis.getUser, Apis.findOne)
  app.use('/admin/update', Apis.getUser, Apis.update)
  app.use('/admin/create', Apis.getUser, Apis.create)
  app.use('/admin/remove', Apis.getUser, Apis.remove)
  app.use('/admin/count', Apis.getUser, function (req, res) {
    app.service('admins').Model.count({
      role: req.query.role, del: false
    }).exec((err, count) => {
      if (err) return res.apiErr(10002, { message: '数据库错误'})
      res.apiCb({total: count})
    })
  })
  app.use('/role/find', Apis.getUser, Apis.find)
  app.use('/role/findOne', Apis.getUser, Apis.findOne)
  app.use('/role/update', Apis.getUser, Apis.update)
  app.use('/role/create', Apis.getUser, Apis.create)
  app.use('/role/remove', Apis.getUser, Apis.remove)

  app.use('/app/find', Apis.getUser, Apis.find)
  app.use('/app/findOne', Apis.getUser, Apis.findOne)
  app.use('/app/update', Apis.getUser, Apis.update)
  app.use('/app/enable', Apis.getUser, function (req, res) {
    var post = req.body
    app.service(req.modelName).Model.update({
      _id: {$in: post._id}
    }, {
      $set: {enable: post.enable }
    }, {
      multi: true
    }).then(rs => {
      res.dbCall(null, rs)
    }).catch(err => {
      return res.apiErr(10002, { message: '数据库错误' + err})
    })
  })
  app.use('/app/create', Apis.getUser, Apis.create)
  app.use('/app/remove', Apis.getUser, Apis.remove)

  app.use('/log/find', Apis.getUser, Apis.find)

}
